/***************************************************************
                       cb_display.c
was cbmap.c - displays the CB map and associated windows.
****************************************************************/
#include <stdio.h>
#include <malloc.h>
#include <time.h>
#include <pwd.h>
#include "clam.h"
#include <gtk/gtkwidget.h>

#define TOP 11
#define ZWIDTHPERCOL 2.5
#define Show {if (graphActivate(g99)){graphRedraw();}}
#define Show_pop {if (graphActivate(g99)){graphPop(); graphRedraw();}}

extern int FpGelCBpicked;

extern void show_help();
extern BOOL bury();
extern void move_selected(), highlightnodraw(); /** fpp functions **/
extern void okMenu(), cloneHigh();
extern void Zagain_zap(),ZhighP();
extern void Zfree_cb_data_structures(), Zadd_clhigh(), Zclamdump();
extern void quitClamA(),quitClamB(),quitClamC(),quitClam2();
extern void Zdump_matrix();
extern int Zbcm(), get_Zset(), Zget_tol(),  Zget_clhigh(), loadCz(), find_Zgroup();
extern void refresh_all_track_colors();
extern int Ztrace_clhigh;
extern GtkWidget *ctg_window;

int Zsign, Zn_align; /* For Build option from Contig Analysis, or Align from CBmap */

static void linemove(), justdohigh(), vertdrag(), horzdrag(), bardrag();

extern Graph g996; /* ok */
static Graph g999, g997;
static int colstart=0;
static float yshift=0.0, zoom=1.0, sizecol=1.0;
static int vscrollbox, scrollbox;
static char scoreText[60], dateText[60];
static int exdo=0, stop, align[10], max_align=10;
static int offset,  height;
static BOOL hozbar;
static int lastI, highI;
static int showfriends=0;
static int showQs=0;

#define BAR 5.0
static int barbox, barline, bar_position;
static float Scr, cbscale;

void drawCBmap(), extraZap(), infoZap(), bandZap(), okMenu();

/**************************************************************
      clean everything but CB map; new map but use window 
**************************************************************/
void cleanCB() 
{
  if(graphActivate(g996)) graphDestroy(); /* ok */
  if(graphActivate(g997)) graphDestroy(); /* bands */
  if(graphActivate(g999)) graphDestroy(); /* extra */
  Zfree_cb_data_structures(); 
  Zsort=1;
  Zn_align=0; Zsign=0;
  lastI = highI = -1;
  zoom=1;
}
/**************************************************************
called from CB window quit, or quitting the analysis window quits all windows
***************************************************************/
void quitCB() 
{
  if(graphActivate(g99)) {
     graphDestroy();
     cleanCB();
  }
  LastCB=NoCB;
}
/**************************************************************/
void quitZap()  /* called by main window Clean Up */
{
  quitCB();
  quitClamA();
  quitClamB();
  quitClamC();
  quitClam2();
}
/**************************************************************/
void trailZap() /* called when trail is turned off - hoz2disp (437) */
{
   if (graphExists(g99)) {
      clhigh = NULL; /* i think this routine is called before fpp sets clhigh */
      lastI = highI = -1;
      drawCBmap();
      if (graphExists(g999)) extraZap();
   }
}
/**************************************************************/
void QsZap() 
{
   if (graphExists(g99)) {
      showQs=1;
      drawCBmap();
   }
}
/**************************************************************/
void showZap() 
{
   if (graphExists(g99)) {
      showfriends=1;
      drawCBmap();
   }
}
/**************************************************************/
void clearZap() 
{
   if (graphExists(g99)) {
      showfriends=0;
      showQs=0;
      drawCBmap();
   }
}
/**************************************************************
find highlight clone and display cbmap centered on it
**************************************************************/
void findout() 
{
int j, i, found;
void cbmap_sort();

   if (!clhigh) return;
   if (graphExists(g99)) {
       highI = -1;
       for (found=j=0; j< ZZ.size && !found; j++) 
       {   
           if (ZZ.matrix[j].cin == clhigh->next) {
              if (ZZ.matrix[j].cbmap>=0) {
                highI = j;
                i = ZS;
                ZS = ZZ.matrix[j].cbmap;
                if (ZS!=i) cbmap_sort();
                found=1;
              }
              else if (ZZ.matrix[j].cbmap==ZIGNORED) 
                 printf("Clone %s is ignored clone\n",arrp(acedata, clhigh->next, CLONE)->clone);
              else  
                 printf("Clone %s is not in a CBmap\n",arrp(acedata, clhigh->next, CLONE)->clone);
           }
       }
       if (found) {
          if (ZZ.matrix[highI].box == 0)
          {
           for (i=found=0; i<Zset[ZS].n_clone && !found; i++)
             if (highI == Zset[ZS].csort[i].i) {
               colstart=i;
               found=1;
               drawCBmap();
             }
          }
       }
   }
}
/**************************************************************
                    DEF: redrawCBmap
called from gtkctgdisplay.c  when clone picked 
may have already highlighted if conpick called fpp called here.
*************************************************************/
void redrawCBmap() 
{
int j, i, found;

   if (clhigh==NULL) return; /* may not be necessary but.. */
                  
   if (ZS != -1 && graphActivate(g99)) {
       highI = -1;
       for (found=j=0; j< ZZ.size && !found; j++) 
       {   
           if (ZZ.matrix[j].cin == clhigh->next) {
              highI = j;
              found=1;
           }
       }
       if (found) {
          if (Zsign && Zadd) Zadd_clhigh();
          if (Ztrace_clhigh == 1) Zdump_matrix(highI);
          if (!Zadd && !Zsign && ZZ.matrix[highI].box == 0)
          {
           for (i=found=0; i<Zset[ZS].n_clone && !found; i++)
             if (highI == Zset[ZS].csort[i].i) {
               colstart=i;
               found=1;
               drawCBmap();
             }
          }
          else if (!Zsign && !showfriends) justdohigh();
          else drawCBmap();
       }
   }
}
/*************************************************************
                  DEF: conpick
user selected something on cb map
***************************************************************/
static void conpick(int box)
{
int i;
struct contig *p;

   if (!graphActivate(g99)) return;
   if (box==0) return;
   if (box == vscrollbox) graphBoxDrag(box, vertdrag);   
   else if (hozbar && box == scrollbox) graphBoxDrag(box, horzdrag);   
   else if (box == barbox) graphBoxDrag(box, bardrag);   
   else {
      for (i=0; i< ZZ.size; i++)
         if (ZZ.matrix[i].box == box) {
             highI = i;
             justdohigh();
             if (ZZ.ctg<=0 && ctg_window==NULL) {
                 if (Ztrace_clhigh == 1) Zdump_matrix(i);
                 return;
             } 
             for (p=root; p!=NULL && p->next != ZZ.matrix[i].cin; p = p->new);
             FpGelCBpicked=3;
             cloneHigh(p, 0);
             if (showfriends) drawCBmap(); /* FIX 5apr99*/
             return;
         }
   }
}
/*****************************************************************
only change highlighting, not redraw entire cb map; reduces flicker
*****************************************************************/
static void justdohigh()
{
  if (!graphActivate(g99)) return;
 
  if (highI != -1 && ZZ.matrix[highI].box != 0) {
	if (ZZ.matrix[highI].cbmap != ZS)
	  graphBoxDraw(ZZ.matrix[highI].box, RED, WHITE);
	else
	  graphBoxDraw(ZZ.matrix[highI].box, BLUE, WHITE);
  }
    if (!trail && lastI != -1 && lastI != highI && ZZ.matrix[lastI].box != 0) 
              graphBoxDraw(ZZ.matrix[lastI].box, BLACK, WHITE);

    if (ZZ.matrix[highI].cbmap != ZS) return;
    if (graphActivate(g999)){
       if (exdo) extraZap(); /* recalculate +,- */
       else {
           if (highI != -1 && ZZ.matrix[highI].ebox != 0) 
                 graphBoxDraw(ZZ.matrix[highI].ebox, WHITE, BLACK);
           if (!trail && lastI != -1 && lastI != highI && ZZ.matrix[lastI].ebox != 0) 
                 graphBoxDraw(ZZ.matrix[lastI].ebox, BLACK, WHITE);
       }
    }
    lastI = highI;
}
/**************************************************************/
void redrawCBmap2() /* called from ctgpick when clone picked from list */
{
int j;
return; /* not being used, but ....*/
   if (!graphActivate(g99)) return;
   if (ZS == -1) return;

   highI = -1;
   for (j=0; j< ZZ.size; j++) 
   {   
       if (ZZ.matrix[j].cin == lastpicked) {
           highI = j;
           break;
       }
   }
   if (highI != -1) {
      if (!Zsign) justdohigh();
      else drawCBmap();
   }
}
/**************************************************************
for horizontal drag bar; put band count to screen coords 
****************************************************************/
static int scr2band(float yscr)
{
float temp;
  if (cbscale!=0.0)
     temp = (((float)yscr - (float)TOP + (yshift*zoom))/cbscale);
  else
     temp = (((float)yscr - (float)TOP + (yshift*zoom)));
  return  (int)(0.5+temp);
}
static float band2scr(int yband)
{
  float ynew = (((float)yband*cbscale) - (yshift*zoom) + (float)TOP);
  return(ynew);
}
/****************************************************************
following are for moving various bars
****************************************************************/
static void horzdrag(float *x, float *y, BOOL isUP)
{
  *y = fpheight+0.25;
  if(isUP) {
      *x = (*x - FPSCALEWIDTH); 
      colstart = (int)((*x/sizecol)+0.5); 
      drawCBmap();   
   }
}
static void vertdrag(float *x, float *y, BOOL isUP)
{
  *x = 0.5;
  if(isUP) {
      *y = *y - TOP;
      yshift = (*y); 
      drawCBmap();  
   }
}
static void bardrag(float *x, float *y, BOOL isUp)
{
  if (!graphActivate(g99)) return;
  *x = (float)BAR-3.5;
  if(isUp){
     *y = *y + 0.5;
     Scr = *y;
     if (Scr < TOP) {Scr = TOP; bar_position = scr2band(Scr);}
     else if (Scr > fpheight) {Scr = fpheight; bar_position = scr2band(Scr);}
     else bar_position = scr2band(Scr);

     graphBoxClear(barbox);
     barbox = graphBoxStart();
     graphRectangle((float)BAR-3.5,Scr-0.5, (float)BAR,Scr+0.5);
     graphBoxEnd();
     graphBoxShift(barline,BAR,Scr);
     graphBoxDraw(barbox,BLACK,TRANSPARENT);
     graphRedraw();
  }
}
static void linemove(int c)
{
  if(c== UP_KEY) bar_position--;
  else if(c == DOWN_KEY) bar_position++;
  else return; 

  Scr = band2scr(bar_position);
  if (Scr < TOP) {Scr = TOP; bar_position = scr2band(Scr);}
  else if (Scr > fpheight) {Scr = fpheight; bar_position = scr2band(Scr);}

  if (!graphActivate(g99)) return;
  graphBoxClear(barbox);
  barbox = graphBoxStart();
  graphRectangle((float)BAR-3.5,Scr-0.5,(float)BAR,Scr+0.5);
  graphBoxEnd();
  graphBoxShift(barline,BAR,Scr);
  graphBoxDraw(barbox,BLACK,TRANSPARENT);
  graphRedraw();
}
/************************************************************/
static int height,oldx;
/****************************************************************************
                    DEF: mapMiddleDrag/Up/Down
*****************************************************************************/
static void mapMiddleDrag (double x, double y)
{
  graphXorLine (oldx, 0, oldx, height) ;
  oldx = x ;
  graphXorLine (oldx, 0, oldx, height) ;
}
static void mapMiddleUp (double x, double y)
{
int width, totalposs, numcol;
int col;

  graphFitBounds(&width,&height); 
  numcol = Zset[ZS].n_clone+Zn_align;
  totalposs = MiN((int)(((float)width - FPSCALEWIDTH)/ZWIDTHPERCOL),numcol);
  col = (int) (x-(double)FPSCALEWIDTH);
  col = col/ZWIDTHPERCOL;
  colstart += col - (totalposs/2);
  drawCBmap();
}
static void mapMiddleDown (double x, double y)
{
  graphXorLine (x, 0, x, height) ;
  oldx = x ;
  graphRegister (MIDDLE_DRAG, mapMiddleDrag) ;  /* must redo */
  graphRegister (MIDDLE_UP, mapMiddleUp) ;
}

/**************************************************************
whole, zoom 
*************************************************************/
static void cmwhole()
{
   zoom = 1.0;
   drawCBmap();
}
static void cmzoomin()
{
   zoom *= 1.5;
   drawCBmap();
}
static void cmzoomout()
{
   zoom /= 1.5;
   if (zoom<1.0) {
       yshift = 0.0;
       zoom = 1.0;
   }
   drawCBmap();
}
/**************************************************************
select ??, again, last, next 
*************************************************************/
static void exZap()
{
   exdo = (exdo==1 ? 0 : 1);
   drawCBmap();
}
static void cmagain()
{
   Zsign=Zn_align=0;
   highI = lastI = -1;
   Zagain_zap();
}
static void cmlast()
{
   if (ZS >0) ZS--;
   else ZS=n_Zset-1;
   Zsign=Zn_align=0;
   highI = lastI = -1;
   drawCBmap();
}
static void cmnext()
{
  if(graphActivate(g999)) graphDestroy();

   if (ZS+1 < n_Zset) ZS++;
   else ZS=0;
   Zsign = Zn_align=0;
   highI = lastI = -1;
   drawCBmap();
}
static void cmstop()
{
   if (!graphActivate(g99)) return;
   Zsign = !Zsign;
   if (Zsign==1) graphBoxDraw(stop, BLACK, RED);
   else graphBoxDraw(stop, BLACK, WHITE);
}
/*****************************************************************
set the clones in the current set to selected
*****************************************************************/
static void cmsel()
{
CLONE *cp;
int k, i;

  for (i=0; i < Zset[ZS].n_clone; i++){ 
     k = Zset[ZS].csort[i].i;
     cp = arrp(acedata, ZZ.matrix[k].cin, CLONE);
     cp->selected = 1;
  }
  if (ctg_window==NULL) return;
  /* fred 5/27/03*/
  refresh_all_track_colors();
}
/*****************************************************************
sort by order of adding to cb, by left end, or by original order
*****************************************************************/
void cbmap_sort()
{
int i, j, k;
struct Zset_csort tmp;

    if (Zset[ZS].csort == NULL) return;
    for (k=i=0; i< ZZ.size && k < Zset[ZS].n_clone; i++) 
       if (ZZ.matrix[i].cbmap == ZS) { /* cari 13feb05 */
           Zset[ZS].csort[k].i = i;
           if (Zsort==0) Zset[ZS].csort[k].left = ZZ.matrix[i].pick;
           else if (Zsort==1 || LastCB==Build) Zset[ZS].csort[k].left = ZZ.matrix[i].leftb;
           else Zset[ZS].csort[k].left = arr(acedata,ZZ.matrix[i].cin, CLONE).x;
           k++;
       }
    for (i=0; i< k-1; i++) 
       for (j=i+1; j< k; j++) 
          if (Zset[ZS].csort[i].left > Zset[ZS].csort[j].left) {
              tmp = Zset[ZS].csort[i];
              Zset[ZS].csort[i] = Zset[ZS].csort[j];
              Zset[ZS].csort[j] = tmp;
          }
}

static void sortclone()
{
   if (Zsort==2) Zsort=0;
   else Zsort++;
   cbmap_sort(); 
   drawCBmap();
   if (graphExists(g999)) extraZap();
}
static void sortmenu1() {Zsort=2; sortclone();}
static void sortmenu2() {Zsort=0; sortclone();}
static void sortmenu3() {Zsort=1; sortclone();}
static void zhelp() {
show_help("/Compute CBmap/CBmap display","cbmap");
}
/************************************************************
                       MAIN: drawCBmap
*************************************************************/
void drawCBmap()
{
  CLONE clone;
  int i,j,k,m,t;
  int width,numcol, availheight, totalposs;
  float widthpercolomn,xpos,ypos, tpos;
  float y,xpt,old, boxscalestart,boxscalelen;
  float col, row, ytop,ybot,scrollstart,scrolllen,hblength,x;
  char str[20],outstr[50], buf[200];
  static MENUOPT cmmenu[] = { {quitCB, "Close"},
    {graphPrint,"Print Screen"}, 
#ifdef CUGI
    /*Zdump, "Stdout Dump",  */
#endif
    { 0, 0 } };
  static MENUOPT sortmenu[] = {
    { sortmenu1, "Build - order added"},
    { sortmenu2, "Left - by left end"},
    { sortmenu3, "Contig - contig order"},
    { 0,0 } };
  static MENUOPT friendsmenu[] = {
    { QsZap, "Show Qs"},
    { showZap, "Show Friends"},
    { clearZap, "Clear All"},
    { exZap, "Show ? (<= Tol) X (<= 2xTol) "},
    { 0,0 } };
  int sortbox;
  char sortlabel[3][10] = {"Build..", "Left...", "Contig."};

  int  C, numrow, last, ex, extra[NBANDS];
  int found, band, e, ee, ii, big;
  struct tm *curr_time;
  time_t ltime;
  
  if(graphActivate(g99)){
      graphClear();
  }
  else{   
      g99 = graphCreate (TEXT_FIT,"CBmap",.2,.2,.47,.8) ;  
      yshift=colstart=0;
      if (Zadd) Zsign=1; 
      else Zsign=0;
      Zn_align=exdo=0; /* nothing fancy unless requested */
      Zsort=1; /* Cari 28mar04 */
      showfriends=0;
      showQs=0;
      Scr = -1;             /* no intial position for vertical line */
      lastI = highI = -1;
  }
  graphRegister(PICK, conpick);
  graphRegister(RESIZE, drawCBmap);
  graphRegister (KEYBOARD, linemove);
  graphRegister (MIDDLE_DOWN, mapMiddleDown);
  graphMenu(cmmenu);

  if (time(&ltime) != -1) {
        curr_time = localtime(&ltime);
        if (!strftime(buf, 200, "%R %a %d %h %Y", curr_time)) 
	      fprintf(stderr, "Warning: Not enough room for time stamp.");
  }
  if (ZZ.ctg!=BIG_NEG_NUM && ZZ.ctg!=0) 
       sprintf(dateText, "%s %d %s", fileName, ZZ.ctg, buf);
  else sprintf(dateText, "%s %d %s", fileName, Zset[ZS].ctg, buf);
  row = 0.5;
  col = 1.0;   graphButton("Whole", cmwhole, col, row);
  col += 7.0;  graphButton("In", cmzoomin, col, row);
  col += 4.0;  graphButton("Out", cmzoomout, col, row);
  col += 5.0;  graphButton("Find High", findout, col, row);
  col += 11.0;  graphButton("EXTRA", extraZap, col, row);
  i = col;
  col += 7.0;  graphButton("BAND", bandZap, col, row);
  col += 6.0;  ex = graphButton("??...", exZap, col, row);
  graphBoxMenu(ex, friendsmenu);
  col += 7.0;  ex = graphButton("Help", zhelp, col, row);

  row += 1.5;
  col = 1.0;   

  if (ZZ.ctg > 0) {
      graphButton("Select", cmsel, col, row);
      col += 8.0;
      if (Zadd)  stop = graphButton(" Add ", cmstop, col, row);
      else  stop = graphButton("Align", cmstop, col, row);
  }
  else col += 8.0;

  if (n_Zset > 1) {
      col += 7.0; graphButton("Next", cmnext, col, row);
      col += 6.0; graphButton("Last", cmlast, col, row);
  }
  col = i; 
  if (LastCB!=Add && LastCB != Fp_order && LastCB != Gel_order)
            graphButton("Again", cmagain, col, row); 
  col += 7.0; sortbox = graphButton(sortlabel[Zsort], sortclone, col, row);
  graphBoxMenu(sortbox, sortmenu);
  col += 9.0; graphButton("OK", okMenu, col, row);

  row += 1.5; graphBoxStart(); graphTextPtr(dateText,1.0,row,42); graphBoxEnd();
  row += 1.0; graphBoxStart(); graphTextPtr(scoreText,1.0,row,60);graphBoxEnd(); /*1oct98*/
  row += 1.5; 

  if (Zadd==1) {
      if (ZS == -1) {
          ZS = get_Zset();
          Zsign=1; 
      }
      sprintf(scoreText,"%s Clones %d CB %d (%6.3f) (%d, %.0e)",
            Fn, Zset[ZS].n_clone, Zset[ZS].n_band,
            (float) Zset[ZS].score,
            ZZ.tol, ZZ.cut); /* 1oct98*/
  }
  else {
      if (ZS == -1) {
          quitCB();
          return;
      }
      if (Zsort!=0) cbmap_sort();
      if (Zsign && highI != -1 && Zn_align <max_align) {
         if (ZZ.matrix[highI].cbmap != ZS) {
            for (i=0; i<Zn_align && align[i]!=highI; i++);
            if (i==Zn_align) {
              align[Zn_align] = highI;
              Zn_align++;
            }
         } 
      }
      if (Zorder)
      sprintf(scoreText,"%s %d/%d clones %d CB %d (%5.3f) (%d, %.0e)",
         Fn, ZS+1, n_Zset, Zset[ZS].n_clone, Zset[ZS].n_band,
           Zset[ZS].score, ZZ.tol,ZZ.cut);
      else
      sprintf(scoreText,"%s %d/%d clones %d CB %d (%s %d, %5.3f) (%d, %.0e)",
         Fn, ZS+1, n_Zset, Zset[ZS].n_clone, Zset[ZS].n_band,
          NOLAP, Zset[ZS].n_Qs, Zset[ZS].score, ZZ.tol,ZZ.cut);
  }
  if (Zset[ZS].n_clone == 0 || Zset[ZS].n_band==0) {
     graphRedraw();
     if (Zadd==1) graphBoxDraw(stop, BLACK, RED);
     if (exdo==1) graphBoxDraw(ex, BLACK, RED);
     else if (showfriends==1 || showQs==1) graphBoxDraw(ex, BLACK, LIGHTRED);
     return;
  }

/* static */
  graphFitBounds(&width,&height); 
  numcol = Zset[ZS].n_clone+Zn_align;
  numrow = Zset[ZS].n_band;
  offset = abs(Zset[ZS].leftb)+1;

  widthpercolomn = ZWIDTHPERCOL;
  totalposs = MiN((int)(((float)width - FPSCALEWIDTH)/widthpercolomn),numcol);

  fpheight = (float)height - 2.0; 
  availheight = height - (TOP + 2.0);

/* dynamic  */
  if(numcol > totalposs) {
     hozbar = TRUE;
     if(colstart+totalposs > numcol)
         colstart = numcol - totalposs;
     else if(colstart < 0)
         colstart = 0;
  }
  else {
     hozbar = FALSE;
     colstart = 0;
  }
  cbscale = ((float)availheight /(float)numrow) * zoom;     
  if(yshift < 0.0)  yshift = 0.0;
  else {
      if (yshift + TOP + ((float)availheight/zoom) > fpheight)
          yshift =  fpheight - (TOP + ((float) availheight/zoom));
  }
  for (i=0; i<ZZ.size; i++) 
         ZZ.matrix[i].box = ZZ.matrix[i].ebox = 0;

/** draw all clone within window range **/
   for (m=0, i=colstart; i< colstart+(totalposs-Zn_align) && 
                         i < Zset[ZS].n_clone; i++, m++) 
   {
      C = Zset[ZS].csort[i].i;
                                                      /* draw name */
      if (clhigh != NULL && ZZ.matrix[C].cin == clhigh->next) highI = C;
      if (C == highI) graphColor(BLUE);
      else if (showfriends && highI != -1 && Zif_exist(highI, C)) graphColor(CLAM);
      else if (showQs==1 && ZZ.matrix[C].cbQ== QALIGN) graphColor(RED);
      else graphColor(BLACK);  

      clone =   arr(acedata, ZZ.matrix[C].cin, CLONE);
      xpos = FPSCALEWIDTH + ((float) m * widthpercolomn); 

      ZZ.matrix[C].box = graphBoxStart();                      
      old = graphTextHeight(0.2);
      
      if (Zsort==0 && ZZ.matrix[C].high_match != -1) {
           if (ZZ.matrix[C].mtype == IAM_APPROX) {
                if (ZZ.matrix[C].cbQ == QALIGN) sprintf(str,"%s~", NOLAP);
                else sprintf(str,"~");
           }
           else {
                if (ZZ.matrix[C].cbQ == QALIGN) sprintf(str,"%s=", NOLAP);
                else sprintf(str,"=");
           }
      }
      else if (ZZ.matrix[C].cbQ == QALIGN) sprintf(str,"%ss", NOLAP);
      else {
          sprintf(str,"%d",(i+1));
          if (i+1 > 999) {
             str[0]=str[1];str[1]=str[2]; str[2]=str[3]; str[3]='\0';
          }
      }
      graphText(str,xpos,row);

      strcpy(outstr,clone.clone);
                       /* CLONE_SZ */
      for (y=row+0.75, j=0; j< 10; j+=2, y+=0.75) 
      {
         if(strlen(outstr)>j){
           strcpy(str,"  ");
           strncpy(str,&(outstr[j]),2);
           graphText(str,xpos,y);
         }
      }
      sprintf(str,"%d",ZZ.matrix[C].n_extra);
      graphText(str,xpos,y);
      old = graphTextHeight(old);

                                               /* bands without ?? */
      for(last=BIG_NEG_NUM, j=0;j< ZZ.matrix[C].n_cb;j++)
      { 
           ypos = ((ZZ.matrix[C].cb_index[j]+offset)*cbscale)+TOP-(yshift*zoom);
           if(ypos > TOP &&  ypos <= (float)fpheight)
           { 
              if (last!=BIG_NEG_NUM) 
                 for (k=last+1; k<ZZ.matrix[C].cb_index[j]; k++) {
                      tpos = ((k+offset) * cbscale) + TOP - (yshift*zoom);
                      graphText("o",xpos,tpos-0.5);
                 }
               last = ZZ.matrix[C].cb_index[j];
               band = Zset[ZS].band[last].avg;
               big = Zgtol(band);

               for (t=0; Zset[ZS].band[last].clone[t] != C; t++)
                     if (t==Zset[ZS].band[last].cnt || t == Zset[ZS].band[last].max) {
                        printf("*** FPC error in cbmap on clone %d band %d\n", C, band);
                        continue;
                     }

               if (abs(band - Zset[ZS].band[last].val[t]) <= big) 
                    graphText("+",xpos,ypos-0.5);
               else graphText("x",xpos,ypos-0.5);
           }
       }
       if (!exdo) goto END_CLONE_LOOP;

                                               /* bands with ?? */ 
      for (j=0; j<ZZ.matrix[C].n_extra; j++) 
           extra[j] = ZZ.matrix[C].extra[j];

                                 /* exterior to clone bounds with exact */
       for (ee=1, last=0, j=ZZ.matrix[C].leftb-1, k=ZZ.matrix[C].rightb+1; 
              (k <= Zset[ZS].rightb || j >= Zset[ZS].leftb) && ee>0;  )
       {
              if (last==0){
                  ii = j;
                  j--;
                  last = 1;
                  if (j < Zset[ZS].leftb) continue;
              }
              else {
                  ii = k;
                  k++;
                  last = 0;
                  if (k > Zset[ZS].rightb) continue;
              }
              band = Zset[ZS].band[ii].avg;
              for (e=ee=found=0; !found && e<ZZ.matrix[C].n_extra ; e++) 
                 if (extra[e]!= -1)
                 {  ee++;
                    big = Zgtol(band);
                    if (abs(band - extra[e]) <= big << 1) {
                        if (abs(band - extra[e]) <=  big) 
                             strcpy(str,"?");
                        else strcpy(str,"X");
                        extra[e] = -1;
                        found = 1;
                    }
                 }
              if (found) {
                 tpos = ((ii+offset) * cbscale) + TOP - (yshift*zoom);
                 if(tpos > TOP &&  tpos <= (float)fpheight)
                    graphText(str,xpos,tpos-0.5);
              }
        }
END_CLONE_LOOP: ;
       graphBoxEnd();
    }                                             /* end draw clones */ 

/** draw align clones **/
    for (k=0; k<Zn_align && m < colstart+totalposs; k++, i++, m++) 
    {
        C = align[k];
        if (C == highI) graphColor(RED);
        else graphColor(BLACK);  
        clone =   arr(acedata, ZZ.matrix[C].cin, CLONE);
        xpos = FPSCALEWIDTH + ((float) m * widthpercolomn); 
        loadCz(&C1z, ZZ.matrix[C].cin);

/**
Changed Gaurav 

#ifdef PARALLEL 
        copyLocalCz(&C1z); // We want to be able to permute the coords 
#endif

*/

        
        ZZ.matrix[C].box = graphBoxStart();                      
        old = graphTextHeight(0.2);
         if (ZZ.ctg!=0) {
            sprintf(str,"  ");
            graphText(str,xpos,row);
         }
        strcpy(outstr,clone.clone);
        for (y=row+0.75, j=0; j< 8; j+=2, y+=0.75) 
        {
           if(strlen(outstr)>j){
             strcpy(str,"    ");
             strncpy(str,&(outstr[j]),2);
             graphText(str,xpos,y);
           }
        }

         for (ii=0, ee=1, j=Zset[ZS].leftb; j <= Zset[ZS].rightb && ee>0; j++)
         {
              band = Zset[ZS].band[j].avg;
              for (e=ee=found=0; !found && e<C1z.nbands; e++) 
                 if (C1z.coords[e]!= -1)
                 {  ee++;
                    if (abs(band - C1z.coords[e]) <= Zgtol(band)) {
                        strcpy(str,"?");
                        C1z.coords[e] = -1;
                        found = 1;
                        ii++;
                    }
                 }
              if (found) {
                 tpos = ((j+offset) * cbscale) + TOP - (yshift*zoom);
                 if(tpos > TOP &&  tpos <= (float)fpheight)
                    graphText(str,xpos,tpos-0.5);
              }
          }
       sprintf(str,"%d",C1z.nbands-ii);
       graphText(str,xpos,y);
       old = graphTextHeight(old);
       graphBoxEnd();
    }
    graphColor(BLACK);  

/****  Draw sliding green vertical bar ****/
    boxscalelen = (float)availheight/zoom; 
    xpt = FPSCALEWIDTH/2.0;
    boxscalestart = yshift +TOP; 
    graphLine(1.0,boxscalestart,xpt,TOP);
    graphLine(1.0,boxscalestart+boxscalelen,xpt,fpheight);
    graphLine(1.0,TOP,1.0,fpheight); 
    graphLine(xpt,TOP,xpt,fpheight); 

    vscrollbox = graphBoxStart();
    graphRectangle(0.5,boxscalestart,1.5,boxscalestart+boxscalelen);
    graphBoxEnd();
    graphBoxDraw(vscrollbox,BLACK,GREEN);

/****  Draw the consensus map ****/
    for(m=0, i=Zset[ZS].leftb;i<=Zset[ZS].rightb;i++){
        y = (float)(i+offset) * cbscale +TOP - (yshift*zoom);
        if (y > TOP && y<= fpheight){
           j = find_Zgroup(i, 0);
           if (j==i) graphLine(xpt-0.5,y,xpt+0.5,y); 
           sprintf(str, "%d ", Zset[ZS].band[i].avg);
           graphText(str,xpt+0.5,y-0.5);
           m++;
        }
    }
/****  draw scale  ****/
    if (m < 40) k=1;
    k = (int) (m/40) + 1.5;
    for(i=Zset[ZS].leftb;i<=Zset[ZS].rightb;i+=k){
        y = (float)(i+offset) * cbscale +TOP - (yshift*zoom);
        if (y > TOP && y<= fpheight){
          sprintf(str, "%d", i);
          graphText(str,2.0,y-0.5);
        }
    }
/*** draw moving horz line ****/
    if (Scr < TOP) {Scr = TOP; bar_position = scr2band(Scr);}
    else if (Scr > fpheight) {Scr = fpheight; bar_position = scr2band(Scr);}
    else bar_position = scr2band(Scr);
   
    barline = graphBoxStart();
    graphLine((float)BAR,Scr,(float)width,Scr);
    graphBoxEnd();
    barbox = graphBoxStart();
    graphRectangle((float)BAR-3.5,Scr-0.5,(float)BAR,Scr+0.5);
    graphBoxEnd();
    graphBoxDraw(barbox,BLACK,TRANSPARENT);

/****  draw horizontal scroll bar if NEEDED ****/
    if(hozbar){
       ytop = fpheight+0.25;
       ybot = fpheight+1.0;
       hblength = (float)totalposs* widthpercolomn;
       sizecol = hblength/(float) numcol;
       for(i=0;i<numcol;i++){
          x = FPSCALEWIDTH + ((float)i*sizecol);
          graphRectangle(x,ytop,x+(sizecol),ybot);
       }      
       scrollstart = FPSCALEWIDTH + (colstart*sizecol);
       scrolllen = ((float)totalposs/(float)numcol)*hblength;
       scrollbox = graphBoxStart();
       graphRectangle(scrollstart,ytop,scrollstart+scrolllen,ybot);
       graphBoxEnd();
       graphBoxDraw(scrollbox,BLACK,GREEN);
    } 
  graphRedraw();
  if (Zsign==1) graphBoxDraw(stop, BLACK, RED);
  if (exdo==1) graphBoxDraw(ex, BLACK, RED);
  else if (showfriends==1 || showQs==1) graphBoxDraw(ex, BLACK, LIGHTRED);
  if(graphExists(g999))  extraZap();
  if(graphExists(g997))  bandZap();
  lastI = highI;
} 
/********************************************************************
                         extraZap
*********************************************************************/
void extraZap()
{
  static MENUOPT menu2[] = {
        { graphDestroy,"Close "},
        { graphPrint, "Print Screen"},
        { 0, 0} } ;
  char c, str1[120];
  float line = 1.0;
  int diff, ctgstart,ptrstart;
  int i, j, k, jj, kk;

  sprintf(str1,"Extras...");
  if(graphActivate(g999)){
    graphClear();
  }
  else{
    g999 = graphCreate (TEXT_SCROLL,str1,.5,.5,.5,.3);
  }
  graphMenu (menu2) ;
  graphTextBounds(5,20);
  ctgstart = 1.0;

  if (exdo) kk = highI;
  else kk = -1;
   
  for (i=0; i < Zset[ZS].n_clone; i++){ 
     k = Zset[ZS].csort[i].i;
     ptrstart = ctgstart + 21.0; 
     ZZ.matrix[k].ebox = graphBoxStart();
     sprintf(str1,"%3d %15s:",i+1, arr(acedata,ZZ.matrix[k].cin,CLONE).clone); /* CLONE_SZ*/
     graphText(str1,ctgstart,line);

     for (j=0; j<ZZ.matrix[k].n_extra; j++) {
         c = ' ';
         if (kk!=-1 && kk != k) {
            for (jj=0; jj<ZZ.matrix[kk].n_extra; jj++) {
               diff = ZZ.matrix[kk].extra[jj] - ZZ.matrix[k].extra[j];
               if (Ztol(ZZ.matrix[kk].extra[jj], diff))
               {  if (diff > 0) c = '+';
                  else c = '-';
                  break;
               }
            }
         }
         sprintf(str1,"%d%c",ZZ.matrix[k].extra[j], c);    
         graphText(str1,ptrstart,line);
         ptrstart += 6.0;
     }
     graphBoxEnd();
     if (k == highI) graphBoxDraw(ZZ.matrix[k].ebox, WHITE, BLACK);
     line += 1.0;
  }
  graphTextBounds(15,(int)line);
  graphRedraw();
}
/********************************************************************
                         bandZap
*********************************************************************/
void bandZap()
{
  static MENUOPT menu3[] = {
     { graphDestroy,"Close "}, 
	 { graphPrint, "Print Screen"}, 
	 { 0, 0} } ;
  char  str1[120];
  float line = 2.0;
  int i, j, k, diff, diff2;
  struct Zset_band *sort, tmp;
  int avg, med;

  sprintf(str1,"Band ...");
  if(graphActivate(g997)){
    graphClear();
  }
  else{
    g997 = graphCreate (TEXT_SCROLL,str1,.5,.6,.5,.6);
  }
  graphMenu (menu3) ;
  sort = (struct Zset_band *) calloc(Zset[ZS].n_band, sizeof(struct Zset_band));
  NOMEM2(sort, "sort bands");
  for (k=0, i=Zset[ZS].leftb; i<= Zset[ZS].rightb; i++, k++)
  {    sort[k] = Zset[ZS].band[i];
       sort[k].max = i;
  }
  for (i=0; i<Zset[ZS].n_band-1; i++) 
     for (j=i+1; j < Zset[ZS].n_band; j++)
         if (sort[i].avg > sort[j].avg) {
             tmp = sort[i];
             sort[i] = sort[j];
             sort[j] = tmp;
         }
  graphBoxStart();
  if (Proj.variable) 
    sprintf(str1,"Avg  Diff  Pos Depth High  Low  Span Unc  Median");
  else
    sprintf(str1,"Avg     Diff  Pos Depth  High  Low  Span  Median");
  graphText(str1,2.0, 1.0);
  graphBoxEnd();

  for (i=0; i<Zset[ZS].n_band; i++, line+=1.0) {
     graphBoxStart();
                                 /* mean and median */
     if (sort[i].cnt== 0) avg = 0;
     else avg = sort[i].total / sort[i].cnt;
     for (j=0; j<sort[i].cnt-1; j++)
       for (k=j+1; k<sort[i].cnt; k++)
          if (sort[i].val[j] > sort[i].val[k]) 
          {   med = sort[i].val[j];
              sort[i].val[j] = sort[i].val[k];
              sort[i].val[k] = med;
          }
     j = sort[i].cnt >> 1; 
     if (sort[i].cnt % 2 == 0) 
        med = (sort[i].val[j-1] +  sort[i].val[j]) >> 1;
     else  med = sort[i].val[j];

     if (i==0) diff = diff2 = 0;
     else {
        diff = (sort[i].avg - sort[i-1].avg);
        diff2 = abs(sort[i].max - sort[i-1].max);
     }
     if (Proj.variable) 
      sprintf(str1,"%6d %4d  %4d %4d   %6d %6d  %4d %4d %6d", 
       sort[i].avg, diff, 
       sort[i].max, sort[i].cnt, sort[i].high, sort[i].low,  
       sort[i].high-sort[i].low, Zgtol(sort[i].avg), med);
     else
      sprintf(str1,"%5d  %5d  %4d %3d   %5d %4d  %4d   %5d", 
       sort[i].avg, diff, 
       sort[i].max, sort[i].cnt, sort[i].high, sort[i].low,
       sort[i].high-sort[i].low,  med);
     graphText(str1,1.0,line);
     graphBoxEnd();
  }
  graphTextBounds(15,(int)line);
  graphRedraw();
  free(sort);
}
